<template>
  <div class="cj-clocker">
    <slot :timeInfo="timeInfo"><span >{{ timeString }}</span></slot>
  </div>
</template>

<script>
const format = '%D 天 %H 小时 %M 分 %S 秒';
let matchers = [];
// Miliseconds
matchers.push(/^[0-9]*$/.source);
// Month/Day/Year [hours:minutes:seconds]
matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
// Year/Day/Month [hours:minutes:seconds] and
// Year-Day-Month [hours:minutes:seconds]
matchers.push(/[0-9]{4}([/-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
// Cast the matchers to a regular expression object
matchers = new RegExp(matchers.join('|'));
// Parse a Date formatted has String to a native object

export default {
  name: 'CjClocker',
  components: {},

  props: {
    time: [String, Number],
    format: {
      type: String,
      default: format
    },
    useBjTime: {
      type: Boolean,
      default: false,
    }
  },

  watch: {
    time() {
      this.render();
    }
  },

  data() {
    return {
      timeString: '',
      timeInfo: {
        D: 0,
        H: 0,
        M: 0,
        S: 0,
        W: 0
      },
    };
  },
  mounted() {
    this._interval = null;
    this.$nextTick(() => {
      this.render();
    });
  },
  beforeDestroy() {
    this.stop();
  },

  methods: {
    render() {
      if (!this.time) {
        return;
      }
      this._finalDate = this.parseDateString(this.time);
      this.start();
    },
    update(){
      this.timeInfo = this.getOffset();
      const timeString = this.format.replace('%D', this.timeInfo.D).replace('%H', this.timeInfo.H).replace('%M', this.timeInfo.M).replace('%S', this.timeInfo.S);
      this.timeString = timeString;
      if(this._totalSecsLeft === 0){
        this.stop();
        this.$emit('on-finish')
      }
    },
    start() {
      if (this._interval !== null) {
        clearInterval(this._interval);
      }
      this.update();
      this._interval = setInterval(()=> {
        this.update();
      }, 1000);
    },
    stop() {
      clearInterval(this._interval);
      this._interval = null;
    },
    getCurrentBeijingTimestamp() {
      const now = new Date(); // 获取当前时间
      const utcTime = new Date(now.getTime() + (now.getTimezoneOffset() * 60000)); // 转换为UTC时间
      const beijingTime = new Date(utcTime.getTime() + (8 * 60 * 60 * 1000)); // 转换为北京时间
      return beijingTime.getTime(); // 返回北京时间的时间戳
    },
    /**
     * 获取传入的时间和当前时间的差值
     */
    getOffset () {
      this._totalSecsLeft = this._finalDate.getTime() - (this.useBjTime ? this.getCurrentBeijingTimestamp() : new Date().getTime()) // In miliseconds
      this._totalSecsLeft = Math.ceil(this._totalSecsLeft / 1000)
      this._totalSecsLeft = this._totalSecsLeft < 0 ? 0 : this._totalSecsLeft;
      //对时分秒进行补0操作
      return {
        S: (this._totalSecsLeft % 60).toString().padStart(2,0),
        M: (Math.floor(this._totalSecsLeft / 60) % 60).toString().padStart(2,0),
        H: (Math.floor(this._totalSecsLeft / 60 / 60) % 24).toString().padStart(2,0),
        D: (Math.floor(this._totalSecsLeft / 60 / 60 / 24)).toString().padStart(2,0),
        W: Math.floor(this._totalSecsLeft / 60 / 60 / 24 / 7),
        months: Math.floor(this._totalSecsLeft / 60 / 60 / 24 / 30),
        years: Math.floor(this._totalSecsLeft / 60 / 60 / 24 / 365)
      }
  },
    /**
     * 将时间转化成Date对象
     * @param dateString
     */
    parseDateString(dateString) {
      // Pass through when a native object is sent
      if (dateString instanceof Date) {
        return dateString;
      }
      // Caste string to date object
      if (String(dateString).match(matchers)) {
        // If looks like a milisecond value cast to number before
        // final casting (Thanks to @msigley)
        if (String(dateString).match(/^[0-9]*$/)) {
          dateString = Number(dateString);
        }
        // Replace dashes to slashes
        if (String(dateString).match(/-/)) {
          dateString = String(dateString).replace(/-/g, '/');
        }
        return new Date(dateString);
      } else {
        throw new Error("Couldn't cast `" + dateString + '` to a date object.');
      }
    }
  }
};
</script>

<style scoped>
.cj-clocker {
  display: inline-block;
}
</style>
